{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ripple texture demo\n",
    "\n",
    "*<<< check out other demo models [here](https://github.com/FullControlXYZ/fullcontrol/tree/master/models/README.md) >>>*\n",
    "  \n",
    "press ctrl+F9 to run all cells in this notebook, or press shift+enter to run each cell sequentially \n",
    "\n",
    "if you change one of the code cells, make sure you run it and all subsequent cells again (in order)\n",
    "\n",
    "*this document is a jupyter notebook - if they're new to you, check out how they work: [link](https://www.google.com/search?q=ipynb+tutorial), [link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb), [link](https://colab.research.google.com/)*\n### be patient :)\n\nthe next code cell may take a while because running it causes several things to happen:\n- connect to a google colab server -> download the fullcontrol code -> install the fullcontrol code\n\ncheck out [other tutorials](https://github.com/FullControlXYZ/fullcontrol/blob/master/tutorials/README.md) to understand the python code for the FullControl design"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if 'google.colab' in str(get_ipython()):\n  !pip install git+https://github.com/FullControlXYZ/fullcontrol --quiet\nimport fullcontrol as fc\nfrom google.colab import files\n",
    "from math import cos, tau, sin\n",
    "from copy import deepcopy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# printer/gcode parameters\n",
    "\n",
    "design_name = 'ripples'\n",
    "nozzle_temp = 210\n",
    "bed_temp = 40\n",
    "print_speed = 500\n",
    "fan_percent = 100\n",
    "printer_name='prusa_i3' # generic / ultimaker2plus / prusa_i3 / ender_3 / cr_10 / bambulab_x1 / toolchanger_T0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# design parameters\n",
    "\n",
    "inner_rad= 15\n",
    "# Inner Radius (mm) - Radius of the inner circle - 'star tip' and 'bulge' parameters morph the geometry radially outwards from this value\n",
    "# default value: 15 ; guideline range: 10 to 30\n",
    "\n",
    "height = 40\n",
    "# Height (mm) - Height of the part\n",
    "# default value: 40 ; guideline range: 20 to 80\n",
    "\n",
    "skew_percent = 10\n",
    "# Twist (%) - How much does the structure twist over its height? 100% means one full rotation anti-clockwise\n",
    "# default value: 10 ; guideline range: -100 to 100\n",
    "\n",
    "star_tips = 4\n",
    "# Star Tips - The number of outward protrusions from a nominally circular geometry - to make a star-like shape\n",
    "# default value: 4 ; guideline range: 0 to 10\n",
    "\n",
    "tip_length = 5\n",
    "# Star Tip Length (mm) - How much does each 'star tip' protrude beyond the inner radius?\n",
    "# default value: 5 ; guideline range: -20 to 20\n",
    "\n",
    "bulge = 2\n",
    "# Bulge (mm) - The geometry bulges out by this amount half way up the structure\n",
    "# default value: 2 ; guideline range: -20 to 20\n",
    "\n",
    "nozzle_dia = 0.4\n",
    "# Nozzle Diameter (mm) - This is used to set a reasonable value for layer height and extrusion rate\n",
    "# default value: 0.4 ; guideline range: 0.3 to 1.2\n",
    "\n",
    "ripples_per_layer = 50\n",
    "# Ripples Per Layer - Number of in-out waves the nozzle performs for each layer. There is actually an extra half-ripple for each layer so that the ripples are offset for each alternating layer\n",
    "# default value: 50 ; guideline range: 20 to 100\n",
    "\n",
    "rip_depth = 1\n",
    "# Ripple Depth (mm) - How far the nozzle moves in and out radially for each 'ripple'\n",
    "# default value: 1 ; guideline range: 0 to 5\n",
    "\n",
    "shape_factor = 1.5\n",
    "# Start Tip Pointiness - This affects how pointy the 'star tips' are and can achieve very interesting geometries\n",
    "# default value: 1.5 ; guideline range: 0.25 to 5\n",
    "\n",
    "\n",
    "RippleSegs = 2 # 2 means the ripple is zig-zag. increase this value to create a smooth wave, but watch out since the generation time will increase\n",
    "first_layer_E_factor = 0.4 # set to be 1 to double extrusion by the end of the layer, 0.4 adds 40%, which seemed good for me\n",
    "centre_x, centre_y = 50, 50"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate the design (make sure you've run the above cells before running this cell)\n",
    "\n",
    "EW = nozzle_dia*2.5\n",
    "EH = nozzle_dia*0.6\n",
    "centre = fc.Point(x=0, y=0, z=0)\n",
    "centre_now = deepcopy(centre)\n",
    "layers = int(height/EH)\n",
    "layer_segs = (ripples_per_layer+0.5)*RippleSegs\n",
    "total_segs = layer_segs*layers\n",
    "\n",
    "# offset the whole procedure to a convenient position on the print bed. initial_z dictates the gap between the nozzle and the bed for the first layer, assuming the model was designed with a first layer z-position of 0\n",
    "initial_z = 0.8*EH \n",
    "model_offset = fc.Vector(x=centre_x, y=centre_y, z=initial_z)\n",
    "\n",
    "steps = []\n",
    "steps.append(fc.Printer(print_speed=print_speed/2)) # halve print speed for the first layer\n",
    "for t in range(int(layers*layer_segs)):\n",
    "    t_val = t/layer_segs # tval = 0 to layers\n",
    "    a_now = t_val*tau*(1+(skew_percent/100)/layers)\n",
    "    a_now -= tau/4 # make the print start from front middle (near primer line)\n",
    "    # the next equation (r_now) looks more complicated than it is. basically radius is inner_rad + radial fluctuation due to ripples (1st line) + radial fluctuation due to the star shape (2nd line) + radial fluctuation due to the bulge (3rd line)\n",
    "    r_now = inner_rad + rip_depth*(0.5+(0.5*cos((ripples_per_layer+0.5)*(t_val*tau))))**1 + \\\n",
    "        (tip_length*(0.5-0.5*cos(star_tips*(t_val*tau)))**shape_factor) + \\\n",
    "        (bulge*(sin((centre_now.z/height)*(0.5*tau))))\n",
    "    centre_now.z = t_val*EH\n",
    "    if t_val < 1: # 1st layer\n",
    "        steps.append(fc.ExtrusionGeometry(height=EH+EH*t_val*first_layer_E_factor)) # ramp up extrusion during the first layer since vase mode means the nozzle moves away from the buildplate\n",
    "    if t_val == 1: # other layers\n",
    "        steps.append(fc.ExtrusionGeometry(height=EH)) # reduce to the correct height as soon as the nozzle passes the start point of the previous layer\n",
    "        steps.append(fc.Printer(print_speed = print_speed)) # double print speed after the first layer. this is combined with an instantaneous reduction in extrusion height, meaning volumetric flow rate would remain constant for this transition if first_layer_E_factor=1\n",
    "    steps.append(fc.polar_to_point(centre_now, r_now, a_now))\n",
    "steps = fc.move(steps, model_offset)\n",
    "annotation_pts = []\n",
    "annotation_labels = []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# preview the design\n",
    "\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(zoom=0.4, style='line'))\n",
    "# hover the cursor over the lines in the plot to check xyz positions of the points in the design\n",
    "\n",
    "# uncomment the next line to create a plot with real heights/widths for extruded lines to preview the real 3D printed geometry\n",
    "fc.transform(steps, 'plot', fc.PlotControls(zoom=0.4, style='tube', initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n",
    "\n",
    "# uncomment the next line to create a neat preview (click the top-left button in the plot for a .png file) - post and tag @FullControlXYZ :)\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(neat_for_publishing=True, zoom=0.4,  initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate and save gcode\n",
    "\n",
    "gcode_controls = fc.GcodeControls(\n",
    "    printer_name=printer_name,\n",
    "\n",
    "    initialization_data={\n",
    "        'primer': 'front_lines_then_y',\n",
    "        'print_speed': print_speed,\n",
    "        'nozzle_temp': nozzle_temp,\n",
    "        'bed_temp': bed_temp,\n",
    "        'fan_percent': fan_percent,\n",
    "        'extrusion_width': EW,\n",
    "        'extrusion_height': EH})\n",
    "gcode = fc.transform(steps, 'gcode', gcode_controls)\nopen(f'{design_name}.gcode', 'w').write(gcode)\nfiles.download(f'{design_name}.gcode')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### please tell us what you're doing with FullControl!\n",
    "\n",
    "- tag FullControlXYZ on social media ([twitter](https://twitter.com/FullControlXYZ), [instagram](https://www.instagram.com/fullcontrolxyz/), [linkedin](https://www.linkedin.com/in/andrew-gleadall-068587119/), [tiktok](https://www.tiktok.com/@fullcontrolxyz))\n",
    "- email [info@fullcontrol.xyz](mailto:info@fullcontrol.xyz)\n",
    "- post on the [subreddit](https://reddit.com/r/fullcontrol)\n",
    "- post in the [github discussions or issues tabs](https://github.com/FullControlXYZ/fullcontrol/issues)\n",
    "\n",
    "in publications, please cite the original FullControl paper and the github repo for the new python version:\n",
    "\n",
    "- Gleadall, A. (2021). FullControl GCode Designer: open-source software for unconstrained design in additive manufacturing. Additive Manufacturing, 46, 102109. \n",
    "- Gleadall, A. and Leas, D. (2023). FullControl [electronic resource: python source code]. available at: https://github.com/FullControlXYZ/fullcontrol"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
